using BepuPhysics.Collidables;
using BepuPhysics.Trees;
using BepuUtilities;
using BepuUtilities.Memory;
using System.Runtime.CompilerServices;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif

namespace BepuPhysics.CollisionDetection
{
    /// <summary>
    /// 定义可用作宽相位扫描测试的回调的类型。
    /// </summary>
    public interface IBroadPhaseSweepTester
    {
        unsafe void Test(CollidableReference collidable, ref float maximumT);
    }

    partial class BroadPhase
    {
        struct RayLeafTester<TRayTester> : IRayLeafTester where TRayTester : IBroadPhaseRayTester
        {
            public TRayTester LeafTester;
            public Buffer<CollidableReference> Leaves;

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public unsafe void TestLeaf(int leafIndex, RayData* rayData, float* maximumT)
            {
                LeafTester.RayTest(Leaves[leafIndex], rayData, maximumT);
            }
        }

        /// <summary>
        /// 查找光线和叶边界框之间的所有交点。
        /// </summary>
        /// <typeparam name="TRayTester">要在射线-叶边界框交叉点上执行的回调的类型。</typeparam>
        /// <param name="Origin">要投射的光线的原点。</param>
        /// <param name="direction">要投射的光线方向。</param>
        /// <param name="maxumT">射线遍历的最大长度(以方向长度为单位)。</param>
        /// <param name="rayTester">要在射线叶边界框交叉点上执行的回调。</param>
        /// <param name="id">用户指定的射线ID。</param>
        public unsafe void RayCast<TRayTester>(in Vector3 origin, in Vector3 direction, float maximumT, ref TRayTester rayTester, int id = 0) where TRayTester : IBroadPhaseRayTester
        {
            TreeRay.CreateFrom(origin, direction, maximumT, id, out var rayData, out var treeRay);
            RayLeafTester<TRayTester> tester;
            tester.LeafTester = rayTester;
            tester.Leaves = activeLeaves;
            ActiveTree.RayCast(&treeRay, &rayData, ref tester);
            tester.Leaves = staticLeaves;
            StaticTree.RayCast(&treeRay, &rayData, ref tester);
            // 扫描测试仪可能依赖于突变才能发挥作用;将任何突变复制回原始参考。
            rayTester = tester.LeafTester;
        }

        struct SweepLeafTester<TSweepTester> : ISweepLeafTester where TSweepTester : IBroadPhaseSweepTester
        {
            public TSweepTester LeafTester;
            public Buffer<CollidableReference> Leaves;

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public unsafe void TestLeaf(int leafIndex, ref float maximumT)
            {
                LeafTester.Test(Leaves[leafIndex], ref maximumT);
            }

        }

        /// <summary>
        /// 查找扫描边界框和叶边界框之间的任何交点。
        /// </summary>
        /// <typeparam name="TSweepTester">要在扫描叶边界框交叉点上执行的回调类型。</typeparam>
        /// <param name="min">要扫描的框的最小边界。</param>
        /// <param name="max">要扫描的框的最大界限。</param>
        /// <param name="direction">扫掠边界框的方向。</param>
        /// <param name="maxumT">扫掠的最大长度(以方向长度为单位)。</param>
        /// <param name="SweepTester">要在扫掠-树叶边界框交叉点上执行的回调。</param>
        public unsafe void Sweep<TSweepTester>(in Vector3 min, in Vector3 max, in Vector3 direction, float maximumT, ref TSweepTester sweepTester) where TSweepTester : IBroadPhaseSweepTester
        {
            Tree.ConvertBoxToCentroidWithExtent(min, max, out var origin, out var expansion);
            TreeRay.CreateFrom(origin, direction, maximumT, out var treeRay);
            SweepLeafTester<TSweepTester> tester;
            tester.LeafTester = sweepTester;
            tester.Leaves = activeLeaves;
            ActiveTree.Sweep(expansion, origin, direction, &treeRay, ref tester);
            tester.Leaves = staticLeaves;
            StaticTree.Sweep(expansion, origin, direction, &treeRay, ref tester);
            // 扫描测试仪可能依赖于突变才能发挥作用;将任何突变复制回原始参考。
            sweepTester = tester.LeafTester;
        }

        /// <summary>
        /// 查找扫描边界框和叶边界框之间的任何交点。
        /// </summary>
        /// <typeparam name="TSweepTester">要在扫描叶边界框交叉点上执行的回调类型。</typeparam>
        /// <param name="binding ingBox">要扫描的边框。</param>
        /// <param name="direction">扫掠边界框的方向。</param>
        /// <param name="maxumT">扫掠的最大长度(以方向长度为单位)。</param>
        /// <param name="SweepTester">要在扫掠-树叶边界框交叉点上执行的回调。</param>
        public unsafe void Sweep<TSweepTester>(in BoundingBox boundingBox, in Vector3 direction, float maximumT, ref TSweepTester sweepTester) where TSweepTester : IBroadPhaseSweepTester
        {
            Sweep(boundingBox.Min, boundingBox.Max, direction, maximumT, ref sweepTester);
        }

        struct BoxQueryEnumerator<TInnerEnumerator> : IBreakableForEach<int> where TInnerEnumerator : IBreakableForEach<CollidableReference>
        {
            public TInnerEnumerator Enumerator;
            public Buffer<CollidableReference> Leaves;

            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public bool LoopBody(int i)
            {
                return Enumerator.LoopBody(Leaves[i]);
            }
        }

        /// <summary>
        /// 查找边界框和叶边界框之间的任何重叠。
        /// </summary>
        /// <typeparam name="TOverlate Enumerator">要调用重叠的枚举数的类型。</typeparam>
        /// <param name="min">查询框的最小界限。</param>
        /// <param name="max">查询框的最大界限。</param>
        /// <param name="overlate Enumerator">调用重叠的枚举器。</param>
        public unsafe void GetOverlaps<TOverlapEnumerator>(in Vector3 min, in Vector3 max, ref TOverlapEnumerator overlapEnumerator) where TOverlapEnumerator : IBreakableForEach<CollidableReference>
        {
            BoxQueryEnumerator<TOverlapEnumerator> enumerator;
            enumerator.Enumerator = overlapEnumerator;
            enumerator.Leaves = activeLeaves;
            ActiveTree.GetOverlaps(min, max, ref enumerator);
            enumerator.Leaves = staticLeaves;
            StaticTree.GetOverlaps(min, max, ref enumerator);
            // 枚举可能已使枚举数发生变化;请保留这些修改。
            overlapEnumerator = enumerator.Enumerator;
        }

        /// <summary>
        /// 查找边界框和叶边界框之间的任何重叠。
        /// </summary>
        /// <typeparam name="TOverlate Enumerator">要调用重叠的枚举数的类型。</typeparam>
        /// <param name="binding ingBox">查询框边界。</param>
        /// <param name="overlate Enumerator">调用重叠的枚举器。</param>
        public unsafe void GetOverlaps<TOverlapEnumerator>(in BoundingBox boundingBox, ref TOverlapEnumerator overlapEnumerator) where TOverlapEnumerator : IBreakableForEach<CollidableReference>
        {
            BoxQueryEnumerator<TOverlapEnumerator> enumerator;
            enumerator.Enumerator = overlapEnumerator;
            enumerator.Leaves = activeLeaves;
            ActiveTree.GetOverlaps(boundingBox, ref enumerator);
            enumerator.Leaves = staticLeaves;
            StaticTree.GetOverlaps(boundingBox, ref enumerator);
            // 枚举可能已使枚举数发生变化;请保留这些修改。
            overlapEnumerator = enumerator.Enumerator;
        }
    }
}
